#include "header.h"

// 实现一个基于线程池的 TCP 服务器

class Task
{
public:
    using callback_t = function<void(int, uint16_t, string)>;
    Task(int sock, int port, string ip, callback_t fun)
        : msock(sock)
        , mport(port)
        , mip(ip)
        , mrun(fun)
    {}

    void run()
    {
        mrun(msock, mport, mip);
    }

private:
    string mip;
    uint16_t mport;
    int msock;
    callback_t mrun;
};

class Server 
{
public:
    Server(uint16_t port = 44444)
        : mport(port)
        , mip()
        , mlisSock(-1)
        , mthdPool(nullptr)
    {}

    // 服务器的初始化
    void init()
    {
        // 1. 创建监听套接字
        mlisSock = socket(AF_INET, SOCK_STREAM, 0);
        // 2. 绑定
        struct sockaddr_in svr;
        memset(&svr, 0, sizeof svr);

        svr.sin_family = AF_INET;
        svr.sin_port = htons(mport);
        svr.sin_addr.s_addr = htonl(INADDR_ANY);        // 自行选择一个
        if (bind(mlisSock, (const struct sockaddr*) &svr, sizeof svr) != 0)
            cout << "绑定失败" << endl;
        cout << "绑定成功" << endl;
        // 3. 开始监听
        if (listen(mlisSock, 5) == 0)
            cout << "开始监听" << endl;
        else
        {
            cout << "监听失败" << endl;
            exit(1);
        }
    }

    void run()
    {
        // 创建线程池, 开始运行
        mthdPool = ThreadPool<Task>::getInstance();
        mthdPool->start();

        while (true)
        {
            // 客户端的相关数据
            struct sockaddr_in peer;
            socklen_t len = sizeof peer;
            memset(&peer, 0, len);

            // 开始监听
            int peersock = accept(mlisSock, (struct sockaddr*) &peer, &len);
            if (peersock == -1)
            {
                cout << "接收请求失败" << endl;
                exit(1);
            }
            cout << "成功从队列中取出一份连接: " << peersock << endl; 
            // 监听成功之后, 就会获取到这个客户端的数据
            int peerPort = ntohl(peer.sin_port);
            string peerIp = inet_ntoa(peer.sin_addr);

            // 有了客户端的数据之后, 就可以构建一个任务, 然后交给线程池去执行了
            // 绑定 Server 里面提供的函数, 就是 Task 需要在线程池中执行的任务
            Task task(peersock, peerPort, peerIp, std::bind(&Server::handleServer, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
            mthdPool->push(task);
            cout << "成功将这个连接和任务添加到线程池中" << endl;
        }
    }

    // 服务器来处理这个从监听池里拿出来的连接
    void handleServer(int sock, uint16_t port, string ip)
    {
        char recvmsg[1024];
        while (true)
        {
            int rd = read(sock, recvmsg, 1024 - 1);
            cout << "rd: " << rd << endl;
            if (rd > 0) 
            {
                cout << "收到了客户端发送的数据: " << recvmsg << endl;
                // 然后将数据小写转大写发送回去
                string sendmsg = recvmsg;
                for (int i = 0; i < sendmsg.length(); i ++)
                {
                    if (isalpha(sendmsg[i]) && islower(sendmsg[i]))
                        sendmsg[i] = toupper(sendmsg[i]);
                }
                cout << "服务器向客户端发送回复：" << sendmsg << endl;
                write(sock, sendmsg.c_str(), sendmsg.length());
            }
            else if (rd == 0)
            {
                cout << "客户端连接都关闭了" << endl;
                break;
            }
        }
        close(sock);        // 服务结束, 关闭这个文件描述符
    }



private:
    uint16_t mport;         // 服务器端口
    string mip;             // 服务器 ip
    int mlisSock;           // 监听套接字
    ThreadPool<Task>* mthdPool; // 线程池指针
};

int main()
{
    Server svr;
    svr.init();
    svr.run();
    return 0;
}